// version V1.0.0
// 触摸驱动函数，配合HAL库使用，已经初始化了I2C 以及外部中断
// i2c不能设置快速模式400K 用的默认模式100K

#include "ft5446u.h"
#include "i2c.h"
#include "stm32f4xx_hal_i2c.h"
#include "cmsis_os.h"


_m_tp_dev tp_dev;

const uint16_t FT5206_TPX_TBL[CT_MAX_TOUCH] = {FT_TP1_REG, FT_TP2_REG, FT_TP3_REG, FT_TP4_REG, FT_TP5_REG};
uint8_t g_gt_tnum = CT_MAX_TOUCH; // 默认支持的触摸屏点数(5点触摸)

// 设置内部上拉，下降沿触发
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    // 检查是哪个引脚触发了中断
    if (GPIO_Pin == TOUCH_INT_Pin)
    {
        DBG("HAL_GPIO_EXTI_Callback\n");

        GPIO_PinState pinState = HAL_GPIO_ReadPin(TOUCH_INT_GPIO_Port, TOUCH_INT_Pin);
        if (pinState == GPIO_PIN_SET)
        {
            // 上升沿
//            DBG("Rising edge\n");
            tp_dev.user_begin = false;
        }
        else
        {
            // 下降沿
//            DBG("Falling edge\n");
            tp_dev.user_begin = true;
        }
    }
}

uint8_t FT5446U_WR_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    HAL_StatusTypeDef status;
    uint8_t data[1 + len]; // 寄存器地址 + 数据

    // 设置要发送的数据
    data[0] = reg & 0XFF; // 寄存器地址

    for (uint8_t i = 0; i < len; i++)
    {
        data[i + 1] = buf[i]; // 数据
    }

    // 发送寄存器地址和数据
    status = HAL_I2C_Master_Transmit(&hi2c1, FT_CMD_WR, data, sizeof(data), 10);
    if (status != HAL_OK)
    {
        // 处理传输错误
        return 1; // 返回非零值表示错误
    }

    return 0; // 返回零表示成功
}
// HAL I2C 读取函数
uint8_t FT5446U_RD_Reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    HAL_StatusTypeDef status;

    uint8_t data[1]; // 寄存器地址 + 数据
    // 设置要发送的数据
    data[0] = reg & 0XFF; // 寄存器地址

    // 发送寄存器地址
    status = HAL_I2C_Master_Transmit(&hi2c1, FT_CMD_WR, data, 1, 10);
    if (status != HAL_OK)
    {
        // 处理传输错误
        return 1; // 返回非零值表示错误
    }

    // 读取数据
    status = HAL_I2C_Master_Receive(&hi2c1, FT_CMD_RD, buf, len, 10);
    if (status != HAL_OK)
    {
        // 处理接收错误
        return 1; // 返回非零值表示错误
    }

    return 0; // 返回零表示成功
}

// 初始化FT5206触摸屏
void FT5446U_Init(void)
{
    uint8_t temp[5];

    // 初始化已经拉低了
    osDelay(10);  // 保持 10ms
    HAL_GPIO_WritePin(TOUCH_RST_GPIO_Port, TOUCH_RST_Pin, GPIO_PIN_SET);   // 拉高复位引脚
    osDelay(50); // 等待复位完成，大约 50ms

    FT5446U_WR_Reg(FT_DEVIDE_MODE, temp, 1);  // 进入正常操作模式
    FT5446U_WR_Reg(FT_ID_G_MODE, temp, 1);    // 查询模式
    temp[0] = 22;                            // 触摸有效值，22，越小越灵敏
    FT5446U_WR_Reg(FT_ID_G_THGROUP, temp, 1); // 设置触摸有效值
    temp[0] = 12;                            // 激活周期，不能小于12，最大14
    FT5446U_WR_Reg(FT_ID_G_PERIODACTIVE, temp, 1);

    // 读取版本号，参考值：0x0001,至于为什么是0x0001 不知道，立创自带的GD32 打印出来是0x0001，所以这个读出来跟它们一样就认为是对的
    FT5446U_RD_Reg(FT_ID_G_LIB_VERSION, &temp[0], 2);
    DBG("CTP ID:0x%04x\r\n", ((uint16_t)temp[0] << 8) + temp[1]);
}

// 扫描触摸屏(采用查询方式)
// mode:0,正常扫描.
// 返回值:当前触屏状态.
// 0,触屏无触摸;1,触屏有触摸
uint8_t FT5446U_Scan(uint8_t mode)
{
    uint8_t buf[4];
    uint8_t i = 0;
    uint8_t res = 0;
    uint8_t temp;
    uint16_t tempsta;

    FT5446U_RD_Reg(FT_REG_NUM_FINGER, &mode, 1); // 读取触摸点的状态
    if ((mode & 0XF) && ((mode & 0XF) <= g_gt_tnum))
    {
        temp = 0XFF << (mode & 0XF); // 将点的个数转换为1的位数,匹配tp_dev.sta定义
        tempsta = tp_dev.sta;        // 保存当前的tp_dev.sta值
        tp_dev.sta = (~temp) | TP_PRES_DOWN | TP_CATH_PRES;
        tp_dev.x[g_gt_tnum - 1] = tp_dev.x[0]; // 保存触点0的数据,保存在最后一个上
        tp_dev.y[g_gt_tnum - 1] = tp_dev.y[0];
        // delay_1ms(4);    //必要的延时，否则老是认为有按键按下
        for (i = 0; i < g_gt_tnum; i++)
        {
            if (tp_dev.sta & (1 << i)) // 触摸有效?
            {
                FT5446U_RD_Reg(FT5206_TPX_TBL[i], buf, 4); // 读取XY坐标值
                if (tp_dev.touchtype & 0X01)              // 横屏
                {
                    tp_dev.y[i] = ((uint16_t)(buf[0] & 0X0F) << 8) + buf[1];
                    tp_dev.x[i] = ((uint16_t)(buf[2] & 0X0F) << 8) + buf[3];
                }
                else
                {
                    tp_dev.x[i] = (((uint16_t)(buf[0] & 0X0F) << 8) + buf[1]);
                    tp_dev.y[i] = ((uint16_t)(buf[2] & 0X0F) << 8) + buf[3];
                }
            }
        }
        res = 1;
        if (tp_dev.x[0] > ACTIVE_WIDTH || tp_dev.y[0] > ACTIVE_HEIGHT) // 非法数据(坐标超出了)
        {
            if ((mode & 0XF) > 1) // 有其他点有数据,则复第二个触点的数据到第一个触点.
            {
                tp_dev.x[0] = tp_dev.x[1];
                tp_dev.y[0] = tp_dev.y[1];
            }
            else // 非法数据,则忽略此次数据(还原原来的)
            {
                tp_dev.x[0] = tp_dev.x[g_gt_tnum - 1];
                tp_dev.y[0] = tp_dev.y[g_gt_tnum - 1];
                mode = 0X80;
                tp_dev.sta = tempsta; // 恢复tp_dev.sta
            }
        }
    }

    if ((mode & 0X1F) == 0) // 无触摸点按下
    {
        if (tp_dev.sta & TP_PRES_DOWN) // 之前是被按下的
        {
            tp_dev.sta &= ~TP_PRES_DOWN; // 标记按键松开
        }
        else // 之前就没有被按下
        {
            tp_dev.x[0] = 0xffff;
            tp_dev.y[0] = 0xffff;
            tp_dev.sta &= 0XE0; // 清除点有效标记
        }
    }
    return res;
}

/**********************************************************
 * 函 数 名 称：letgo_scan
 * 函 数 功 能：触摸松手判断
 * 传 入 参 数：contact：第几个触点(一共有5个触点)
 * 				(sx,sy)：判断触摸地的起始坐标
 * 				(ex,ey)：判断触摸地的结束坐标
 * 函 数 返 回：无
 * 作       者：LCKFB
 * 备       注：无
**********************************************************/
void letgo_scan(uint16_t contact,uint16_t sx, uint16_t sy,uint16_t ex, uint16_t ey)
{
    //等待松手
    while( FT5446U_Scan(0) )
    {
        //如果离开了x轴触摸范围
        if( tp_dev.x[contact] <= sx || tp_dev.x[contact] >= ex )
        {
            return;
        }
        //如果离开了y轴触摸范围
        if( tp_dev.y[contact] <= sy && tp_dev.y[contact] >= ey )
        {
            return;
        }
    }
}